#ifndef __open_vip_msg_dev_ram__
#define __open_vip_msg_dev_ram__
#pragma once

#include "openvip/message.h"

namespace ovip {

class DevMsgRam : public Device
{
public:
    SimpleMemory mem;
    DevMsgRam(std::string name, u_int block_count = 4,
                 u_int chunk_size = 1024, u_char default_value = 0) :
        mem(name, block_count, chunk_size, default_value), Device(name)
    {}
    bool IsSlave() override { return true; }
    bool Handle(Message &pmsg) override
    {
        auto msg = (MemBusMsg &)pmsg;
        if (msg.IsRead()) {
            auto rsp  = msg.AsReadRsp();
            rsp->data = mem.Read(msg.addr, msg.byte_len);
            this->manager->RespMsg(this->channel, *rsp);
            return true;
        } else if (msg.IsWrite()) {
            mem.Write(msg.addr, msg.byte_len, msg.data);
            auto rsp = msg.AsWriteRsp();
            this->manager->RespMsg(this->channel, *rsp);
            return true;
        } else if (msg.IsBurstRead()) {
            auto addr_blks = msg.fstage * msg.byte_len;
            auto addr_offs = msg.addr % addr_blks;
            auto addr_base = msg.addr - addr_offs;
            auto address = msg.addr;
            for (int i = 0; i < msg.fstage; i++) {
                auto rsp    = msg.AsReadRsp();
                if(msg.IsBurstReadInc()){
                    address  = msg.addr + i*msg.byte_len;
                }else if(msg.IsBurstReadWra()){
                    address = addr_base + (addr_offs + i*msg.byte_len)%addr_blks;
                }else{
                    Assert(false, "BurstRead type not support")
                }
                rsp->addr   = address;
                rsp->data   = mem.Read(address, msg.byte_len);
                rsp->cstage = i;
                this->manager->RespMsg(this->channel, *rsp);
            }
            return true;
        } else if (msg.IsBurstWrite()) {
            auto addr_blks = msg.fstage * msg.byte_len;
            auto addr_offs = msg.addr % addr_blks;
            auto addr_base = msg.addr - addr_offs;
            auto address = msg.addr;
            if(msg.IsBurstWriteInc()){
                address += msg.cstage * msg.byte_len;
            }else if(msg.IsBurstWriteWra()){
                address = addr_base + (addr_offs + msg.cstage*msg.byte_len)%addr_blks;
            }
            mem.Write(address, msg.byte_len, msg.data);
            if (msg.IsFullStage()) {
                auto rsp = msg.AsWriteRsp();
                this->manager->RespMsg(this->channel, *rsp);
            }
            return true;
        } else {
            Assert(false, "message operation Not implement");
        }
    }
};

} // namespace ovip

#endif
